package pl.bristleback.server.bristle.messages;

import org.apache.log4j.Logger;
import org.jwebsocket.api.WebSocketConnector;
import org.jwebsocket.api.WebSocketEngine;
import org.jwebsocket.api.WebSocketPacket;
import org.jwebsocket.async.IOFuture;
import org.jwebsocket.kit.CloseReason;
import org.jwebsocket.kit.RequestHeader;
import org.jwebsocket.kit.WebSocketSession;
import org.jwebsocket.token.Token;
import org.jwebsocket.token.TokenFactory;

import java.net.InetAddress;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Dispatcher speed testing
 * <p/>
 * Created on: 2010-10-10 11:13:51 <br/>
 *
 * @author Wojciech Niemiec
 */
public class DispatcherSpeedTesting {
  private static Logger log = Logger.getLogger(DispatcherSpeedTesting.class.getName());

  private LinkedBlockingQueue<WebSocketMessage> messages = new LinkedBlockingQueue<WebSocketMessage>();
  private Thread[] producers;
  private Thread consumer;

  private int producerNumber = 5;
  private int maxMessagesPerProducer = 10000;

  private long startTime;

  public DispatcherSpeedTesting() {

    producers = new Thread[producerNumber];
    for (int i = 0; i < producerNumber; i++) {
      producers[i] = new Thread(new Producer(i+1));
    }
    consumer = new Thread(new Consumer());
  }

  public void runThreads() {
    startTime = System.nanoTime();
    consumer.start();
    for (Thread producer : producers) {
      producer.start();
    }
  }

  public static void main(String[] args) {
    DispatcherSpeedTesting test = new DispatcherSpeedTesting();
    test.runThreads();
  }


  private class Producer implements Runnable {

    private Token token = TokenFactory.createToken();
    private WebSocketConnector connector = new FakeConnector();

    private int createdMessagesCount;
    private int sleepTime = 1;
    private int producerNr;

    private Producer(int producerNr) {
      this.producerNr = producerNr;
    }

    @Override
    public void run() {
      try {
        while (createdMessagesCount < maxMessagesPerProducer) {
          messages.add(getMessage());
          createdMessagesCount++;
          Thread.sleep(sleepTime);
        }
        long endTime = System.nanoTime();
        System.out.println("Watek "+producerNr+" zakonczyl prace w czasie "+(endTime-startTime)/1000000+" milisekund od rozpoczecia dzialania");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    private WebSocketMessage getMessage() {
      return new WebSocketMessage(token, connector);
    }
  }

  private class Consumer implements Runnable {
    @Override
    public void run() {
      try {
        int maxMessages = maxMessagesPerProducer * producerNumber;
        int messagesReceived = 0;
        while (messagesReceived < maxMessages) {
          WebSocketMessage message = messages.take();
          if (message != null) {
            message.getToken();
            messagesReceived++;
            if (messagesReceived % maxMessagesPerProducer == 0) {
              System.out.println("Odebralem wiadomosci w liczbie podzielnej przez "+maxMessagesPerProducer+" w czasie: " + (System.nanoTime()-startTime)/1000000+" milisekund od rozpoczecia dzialania");
            }
          }
        }
        long endTime = System.nanoTime();
        System.out.println("Odebralem wszystkie wiadomosci w czasie: "+(endTime-startTime)/1000000+" milisekund od rozpoczecia dzialania");
      } catch (Exception e) {
        e.printStackTrace();
      }

    }
  }

  private class FakeConnector implements WebSocketConnector {
    @Override
    public void startConnector() {
    }

    @Override
    public void stopConnector(CloseReason aCloseReason) {
    }

    @Override
    public WebSocketEngine getEngine() {
      return null;
    }

    @Override
    public void processPacket(WebSocketPacket aDataPacket) {
    }

    @Override
    public void sendPacket(WebSocketPacket aDataPacket) {
    }

    @Override
    public RequestHeader getHeader() {
      return null;
    }

    @Override
    public void setHeader(RequestHeader aHeader) {
    }

    @Override
    public Object getVar(String aKey) {
      return null;
    }

    @Override
    public void setVar(String aKey, Object aValue) {
    }

    @Override
    public Boolean getBoolean(String aKey) {
      return null;
    }

    @Override
    public boolean getBool(String aKey) {
      return false;
    }

    @Override
    public void setBoolean(String aKey, Boolean aValue) {
    }

    @Override
    public String getString(String aKey) {
      return null;
    }

    @Override
    public void setString(String aKey, String aValue) {
    }

    @Override
    public Integer getInteger(String aKey) {
      return null;
    }

    @Override
    public void setInteger(String aKey, Integer aValue) {
    }

    @Override
    public void removeVar(String aKey) {
    }

    @Override
    public String generateUID() {
      return null;
    }

    @Override
    public int getRemotePort() {
      return 0;
    }

    @Override
    public InetAddress getRemoteHost() {
      return null;
    }

    @Override
    public String getId() {
      return null;
    }

    @Override
    public WebSocketSession getSession() {
      return null;
    }

    @Override
    public String getUsername() {
      return null;
    }

    @Override
    public void setUsername(String aUsername) {
    }

    @Override
    public void removeUsername() {
    }

    @Override
    public String getNodeId() {
      return null;
    }

    @Override
    public void setNodeId(String aNodeId) {
    }

    @Override
    public void removeNodeId() {
    }

    @Override
    public IOFuture sendPacketAsync(WebSocketPacket webSocketPacket) {
      return null;
    }

    @Override
    public String getSubprot() {
      return null;
    }

    @Override
    public void setSubprot(String s) {
    }

    @Override
    public void removeSubprot() {
    }

    @Override
    public int getVersion() {
      return 0;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void setVersion(int i) {
      //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean isLocal() {
      return false;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean isSSL() {
      return false;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void setSSL(boolean b) {
      //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean isHixie() {
      return false;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean isHybi() {
      return false;  //To change body of implemented methods use File | Settings | File Templates.
    }
  }
}
